import * as fs from 'fs';
import * as path from 'path';

export interface CrossFileUpdateResult {
  success: boolean;
  message: string;
  updatedFiles: Array<{
    filePath: string;
    changesCount: number;
  }>;
  updateDetails?: string[];
  errors?: string[];
}

export interface MethodChange {
  oldMethodName: string;
  newMethodName: string;
  oldSignature?: string;
  newSignature?: string;
}

export interface FileReference {
  filePath: string;
  lineNumber: number;
  content: string;
  type: 'method_call' | 'import' | 'type_reference';
}

/**
 * 跨文件引用更新器 - 当B文件方法变更时自动更新A文件中的引用
 */
export class CrossFileReferenceUpdater {

  async updateReferences(
    targetFilePath: string, 
    projectPath: string, 
    methodChanges?: MethodChange[]
  ): Promise<CrossFileUpdateResult> {
    const result: CrossFileUpdateResult = {
      success: false,
      message: '',
      updatedFiles: [],
      updateDetails: [],
      errors: []
    };

    try {
      console.error(`[CrossFileReferenceUpdater] 开始跨文件引用更新`);
      console.error(`[CrossFileReferenceUpdater] 目标文件: ${targetFilePath}`);
      console.error(`[CrossFileReferenceUpdater] 项目路径: ${projectPath}`);
      
      if (!fs.existsSync(targetFilePath)) {
        result.errors?.push('目标文件不存在');
        result.message = '目标文件不存在';
        return result;
      }

      const targetFileContent = fs.readFileSync(targetFilePath, 'utf-8');
      const targetClassName = this.extractClassName(targetFileContent);
      
      if (!targetClassName) {
        result.errors?.push('无法识别目标文件的类名');
        result.message = '无法识别目标文件的类名';
        return result;
      }

      console.error(`[CrossFileReferenceUpdater] 目标类名: ${targetClassName}`);

      // 如果没有提供方法变更信息，自动检测
      if (!methodChanges || methodChanges.length === 0) {
        methodChanges = await this.detectMethodChanges(targetFilePath);
      }

      console.error(`[CrossFileReferenceUpdater] 方法变更数: ${methodChanges?.length || 0}`);

      // 扫描项目中所有引用目标类的文件
      const referencingFiles = await this.findReferencingFiles(projectPath, targetClassName, targetFilePath);
      console.error(`[CrossFileReferenceUpdater] 找到 ${referencingFiles.length} 个引用文件`);

      if (referencingFiles.length === 0) {
        result.success = true;
        result.message = '没有找到引用目标类的文件';
        return result;
      }

      // 更新每个引用文件
      for (const refFile of referencingFiles) {
        try {
          const updateCount = await this.updateFileReferences(
            refFile.filePath, 
            targetClassName, 
            methodChanges || []
          );
          
          if (updateCount > 0) {
            result.updatedFiles.push({
              filePath: refFile.filePath,
              changesCount: updateCount
            });
            
            result.updateDetails?.push(`${path.basename(refFile.filePath)}: 更新了${updateCount}处引用`);
            console.error(`[CrossFileReferenceUpdater] 更新文件: ${refFile.filePath}, 变更数: ${updateCount}`);
          }
        } catch (error) {
          result.errors?.push(`更新文件 ${refFile.filePath} 失败: ${error}`);
        }
      }

      result.success = true;
      result.message = `成功更新 ${result.updatedFiles.length} 个文件的引用`;

      // 如果有接口模式的更新，还需要更新import语句
      if (this.hasInterfacePattern(targetFileContent)) {
        await this.updateImportStatements(result.updatedFiles, targetClassName);
      }

    } catch (error) {
      result.errors?.push(`跨文件引用更新失败: ${error}`);
      result.message = `跨文件引用更新失败: ${error}`;
      console.error(`[CrossFileReferenceUpdater] 错误:`, error);
    }

    return result;
  }

  private extractClassName(content: string): string | null {
    const match = content.match(/(?:public\s+)?(?:class|interface)\s+(\w+)/);
    return match ? match[1] : null;
  }

  private async detectMethodChanges(targetFilePath: string): Promise<MethodChange[]> {
    // 这里可以实现基于git diff或者其他方式的自动检测
    // 暂时返回空数组，表示只做类名和import的更新
    return [];
  }

  private async findReferencingFiles(
    projectPath: string, 
    targetClassName: string, 
    excludeFilePath: string
  ): Promise<FileReference[]> {
    const references: FileReference[] = [];
    
    // 递归遍历项目目录
    const searchDir = async (dirPath: string) => {
      if (!fs.existsSync(dirPath)) return;
      
      const entries = fs.readdirSync(dirPath, { withFileTypes: true });
      
      for (const entry of entries) {
        const fullPath = path.join(dirPath, entry.name);
        
        if (entry.isDirectory()) {
          // 跳过常见的忽略目录
          if (!this.shouldSkipDirectory(entry.name)) {
            await searchDir(fullPath);
          }
        } else if (entry.isFile() && entry.name.endsWith('.java') && fullPath !== excludeFilePath) {
          const fileReferences = await this.findReferencesInFile(fullPath, targetClassName);
          references.push(...fileReferences);
        }
      }
    };
    
    await searchDir(projectPath);
    return references;
  }

  private shouldSkipDirectory(dirName: string): boolean {
    const skipDirs = [
      'node_modules', '.git', '.idea', '.vscode', 'target', 'build', 
      'dist', 'out', '.gradle', 'bin', 'logs', 'temp', 'tmp'
    ];
    return skipDirs.includes(dirName) || dirName.startsWith('.');
  }

  private async findReferencesInFile(filePath: string, targetClassName: string): Promise<FileReference[]> {
    const references: FileReference[] = [];
    
    try {
      const content = fs.readFileSync(filePath, 'utf-8');
      const lines = content.split('\n');
      
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const lineNumber = i + 1;
        
        // 检查import语句
        if (line.trim().includes(`import `) && line.includes(targetClassName)) {
          references.push({
            filePath,
            lineNumber,
            content: line.trim(),
            type: 'import'
          });
        }
        
        // 检查类型引用
        if (line.includes(targetClassName) && !line.trim().startsWith('//')) {
          // 排除import行，避免重复
          if (!line.trim().startsWith('import ')) {
            references.push({
              filePath,
              lineNumber,
              content: line.trim(),
              type: 'type_reference'
            });
          }
        }
        
        // 检查方法调用（简单检测）
        const methodCallPattern = new RegExp(`\\b${targetClassName}\\s*\\.\\s*(\\w+)\\s*\\(`, 'g');
        const methodMatches = line.matchAll(methodCallPattern);
        
        for (const match of methodMatches) {
          references.push({
            filePath,
            lineNumber,
            content: line.trim(),
            type: 'method_call'
          });
        }
      }
    } catch (error) {
      console.error(`[CrossFileReferenceUpdater] 读取文件失败: ${filePath}`, error);
    }
    
    return references;
  }

  private async updateFileReferences(
    filePath: string, 
    targetClassName: string, 
    methodChanges: MethodChange[]
  ): Promise<number> {
    let changeCount = 0;
    
    try {
      let content = fs.readFileSync(filePath, 'utf-8');
      const originalContent = content;
      
      // 更新方法调用
      for (const change of methodChanges) {
        if (change.oldMethodName && change.newMethodName) {
          // 更新方法调用: targetClassName.oldMethod() -> targetClassName.newMethod()
          const oldCallPattern = new RegExp(
            `\\b${targetClassName}\\s*\\.\\s*${change.oldMethodName}\\s*\\(`,
            'g'
          );
          
          content = content.replace(oldCallPattern, (match) => {
            changeCount++;
            return match.replace(change.oldMethodName, change.newMethodName);
          });
          
          // 更新实例方法调用: instance.oldMethod() -> instance.newMethod()
          const instanceCallPattern = new RegExp(
            `\\b(\\w+)\\s*\\.\\s*${change.oldMethodName}\\s*\\(`,
            'g'
          );
          
          content = content.replace(instanceCallPattern, (match, instanceName) => {
            // 检查实例是否是目标类型
            if (this.isInstanceOfTargetClass(content, instanceName, targetClassName)) {
              changeCount++;
              return match.replace(change.oldMethodName, change.newMethodName);
            }
            return match;
          });
        }
      }
      
      // 如果有变更，写回文件
      if (content !== originalContent) {
        fs.writeFileSync(filePath, content, 'utf-8');
        console.error(`[CrossFileReferenceUpdater] 更新文件: ${filePath}`);
      }
      
    } catch (error) {
      console.error(`[CrossFileReferenceUpdater] 更新文件失败: ${filePath}`, error);
    }
    
    return changeCount;
  }

  private isInstanceOfTargetClass(content: string, instanceName: string, targetClassName: string): boolean {
    // 简单检查实例声明
    const patterns = [
      new RegExp(`\\b${targetClassName}\\s+${instanceName}\\s*[=;]`),
      new RegExp(`@Autowired\\s+(?:private\\s+)?${targetClassName}\\s+${instanceName}`),
      new RegExp(`private\\s+${targetClassName}\\s+${instanceName}`),
      new RegExp(`public\\s+${targetClassName}\\s+${instanceName}`)
    ];
    
    return patterns.some(pattern => pattern.test(content));
  }

  private hasInterfacePattern(content: string): boolean {
    return content.includes('implements ') || content.includes('interface ');
  }

  private async updateImportStatements(updatedFiles: Array<{filePath: string; changesCount: number}>, targetClassName: string): Promise<void> {
    // 更新import语句，从具体类改为接口
    for (const fileInfo of updatedFiles) {
      try {
        let content = fs.readFileSync(fileInfo.filePath, 'utf-8');
        
        // 如果目标类变成了Interface模式，更新import
        const interfaceName = this.generateInterfaceName(targetClassName);
        const implName = this.generateImplName(targetClassName);
        
        // 更新import语句：从实现类import改为接口import
        const importPattern = new RegExp(`import\\s+[^;]*${targetClassName}\\s*;`, 'g');
        content = content.replace(importPattern, (match) => {
          if (match.includes(implName)) {
            return match; // 保持实现类的import
          } else {
            return match.replace(targetClassName, interfaceName);
          }
        });
        
        // 更新类型声明：从具体类改为接口
        const typePattern = new RegExp(`\\b${targetClassName}\\b`, 'g');
        content = content.replace(typePattern, (match, offset) => {
          const beforeMatch = content.substring(Math.max(0, offset - 20), offset);
          const afterMatch = content.substring(offset, offset + match.length + 20);
          
          // 如果是在@Autowired注解后的类型声明，改为接口
          if (beforeMatch.includes('@Autowired') || beforeMatch.includes('private ') || beforeMatch.includes('public ')) {
            return interfaceName;
          }
          
          return match;
        });
        
        fs.writeFileSync(fileInfo.filePath, content, 'utf-8');
        
      } catch (error) {
        console.error(`[CrossFileReferenceUpdater] 更新import失败: ${fileInfo.filePath}`, error);
      }
    }
  }

  private generateInterfaceName(originalClassName: string): string {
    if (originalClassName.endsWith('Service')) {
      return originalClassName; // Service接口保持同名
    }
    return originalClassName + 'Interface';
  }

  private generateImplName(originalClassName: string): string {
    if (originalClassName.endsWith('Service')) {
      const baseName = originalClassName.slice(0, -7);
      return baseName + 'ServiceImpl';
    }
    return originalClassName + 'Impl';
  }

  /**
   * 检测方法签名变更 - 可以通过比较两个版本的文件来实现
   */
  async detectMethodSignatureChanges(oldFilePath: string, newFilePath: string): Promise<MethodChange[]> {
    const changes: MethodChange[] = [];
    
    try {
      if (!fs.existsSync(oldFilePath) || !fs.existsSync(newFilePath)) {
        return changes;
      }
      
      const oldContent = fs.readFileSync(oldFilePath, 'utf-8');
      const newContent = fs.readFileSync(newFilePath, 'utf-8');
      
      const oldMethods = this.extractMethodSignatures(oldContent);
      const newMethods = this.extractMethodSignatures(newContent);
      
      // 检测方法名变更
      oldMethods.forEach(oldMethod => {
        const matchingNew = newMethods.find(newMethod => 
          newMethod.name !== oldMethod.name && 
          this.isSimilarSignature(oldMethod.signature, newMethod.signature)
        );
        
        if (matchingNew) {
          changes.push({
            oldMethodName: oldMethod.name,
            newMethodName: matchingNew.name,
            oldSignature: oldMethod.signature,
            newSignature: matchingNew.signature
          });
        }
      });
      
    } catch (error) {
      console.error(`[CrossFileReferenceUpdater] 检测方法变更失败:`, error);
    }
    
    return changes;
  }

  private extractMethodSignatures(content: string): Array<{name: string, signature: string}> {
    const methods: Array<{name: string, signature: string}> = [];
    const lines = content.split('\n');
    
    for (const line of lines) {
      if (this.isMethodDefinition(line) && line.includes('public ')) {
        const name = this.extractMethodName(line);
        if (name) {
          methods.push({
            name,
            signature: line.trim()
          });
        }
      }
    }
    
    return methods;
  }

  private isMethodDefinition(line: string): boolean {
    const trimmed = line.trim();
    return (trimmed.includes('public ') || trimmed.includes('private ') || trimmed.includes('protected ')) &&
           trimmed.includes('(') && 
           (trimmed.includes('{') || trimmed.endsWith(')'));
  }

  private extractMethodName(line: string): string | null {
    const match = line.match(/\b(\w+)\s*\(/);
    return match ? match[1] : null;
  }

  private isSimilarSignature(sig1: string, sig2: string): boolean {
    // 简单的签名相似度检测 - 比较参数类型和数量
    const params1 = this.extractParameters(sig1);
    const params2 = this.extractParameters(sig2);
    
    if (params1.length !== params2.length) {
      return false;
    }
    
    for (let i = 0; i < params1.length; i++) {
      if (params1[i] !== params2[i]) {
        return false;
      }
    }
    
    return true;
  }

  private extractParameters(signature: string): string[] {
    const match = signature.match(/\(([^)]*)\)/);
    if (!match || !match[1].trim()) {
      return [];
    }
    
    return match[1].split(',').map(param => {
      const parts = param.trim().split(/\s+/);
      return parts.length >= 2 ? parts[parts.length - 2] : '';
    }).filter(Boolean);
  }
}